import React, { useState, useRef, useContext, useCallback } from 'react';
import { Icon, Tooltip, Divider, Modal, message, Spin, Form, Row, Col } from 'antd';
import { useDeepCompareEffect, useRequest } from 'ahooks';
import isPlainObject from 'lodash/isPlainObject';
import Tree, { FilteringContainer, renderers } from 'react-virtualized-tree';
import last from 'lodash/last';
import classnames from 'classnames';
import { getViewPort } from '@/utils/utils';
import ValidatorContext from './ValidatorContext';
import { getNodeById, getAttrPath, serialize } from './utils';
import request from '@/utils/request';
import Node from './components/Node';
import styles from './styles.less';
import SquareButton from '@/components/SquareButton';
import CodeEditor from '@/components/CodeEditor';
import { TreeFilter } from '../Transformer/components/NodePathSelect/utils';

const { Expandable } = renderers;

function stringToJson(ref, format) {
  const editor = ref.current;

  if (editor.hasError()) {
    message.error(`不是合法的${format}格式`);
    return Promise.reject();
  }

  return request.post('/validation/parseNodeTree', {
    data: { format, message: editor.getValue() },
  });
}

function getHeight() {
  const { height } = getViewPort(false);
  const $header = document.getElementById('layout-header');
  const $tabsNav = document.querySelector('.layout-tabs-nav');

  return (
    height -
    ($header === null ? 0 : $header.offsetHeight) -
    ($tabsNav === null ? 0 : $tabsNav.offsetHeight) -
    16 * 2 -
    48 -
    12 * 2 -
    37
  );
}

const height = getHeight();

function ValidatorEditor() {
  const { state, dispatch } = useContext(ValidatorContext);
  const {
    message: importMessage,
    validationId,
    versionId,
    format,
    versionNumber,
    rootNode,
    globalToggle,
    readOnly,
  } = state;

  const [visible, setVisible] = useState(false);

  const importRef = useRef();

  const testRef = useRef();

  const resultRef = useRef();

  const [show, setShow] = useState(false);

  // 展示默认配置面板
  const showDefaultPanel = useCallback(() => {
    const rootNode = {
      nodeName: 'root',
      nodeType: 'Object',
      children: [],
    };
    dispatch({
      type: 'set_the_whole_tree',
      payload: { rootNode: serialize([rootNode])[0] },
    });
  }, [dispatch]);

  // 导入json
  const { loading, run } = useRequest(() => stringToJson(importRef, format), {
    manual: true,
    onSuccess: response => {
      if (isPlainObject(response)) {
        dispatch({
          type: 'set_the_whole_tree',
          payload: {
            rootNode: serialize([response])[0],
            message: importRef.current.getValue(),
          },
        });
        setVisible(false);
        message.success('导入成功');
      } else {
        message.error('预期返回约定格式的对象');
      }
    },
  });

  // 获取版本数据
  const { loading: getDataLoading } = useRequest(
    () =>
      request.get('/validation/queryVersionData', {
        params: { validationId, versionId },
      }),
    {
      onSuccess: data => {
        const { rootNode, ...rest } = data;
        dispatch({
          type: 'set_the_whole_tree',
          payload: {
            ...rest,
            rootNode: rootNode ? serialize([rootNode])[0] : null,
          },
        });
      },
    }
  );

  // 保存版本数据
  const { loading: saveDataLoading, run: handleSave } = useRequest(
    () =>
      request('/validation/saveVersionData', {
        data: { versionId, rootNode, message: importMessage },
      }),
    {
      manual: true,
      onSuccess: () => {
        message.success('保存成功');
      },
    }
  );

  // 校验测试
  const { data: result = {}, loading: testLoading, run: runTest } = useRequest(
    () =>
      request.post('/validation/run', {
        data: { format, message: testRef.current.getValue(), rootNode },
      }),
    {
      manual: true,
    }
  );

  useDeepCompareEffect(() => {
    if (isPlainObject(rootNode)) {
      dispatch({
        type: 'set_the_whole_tree',
        payload: { rootNode: serialize([rootNode])[0] },
      });
    }
  }, [rootNode]);

  return (
    <Spin spinning={getDataLoading}>
      <div className={styles.jsonEditor}>
        <div className={classnames(styles.toolbar, 'clearfix')}>
          <div className="pull-left bold padding-left" style={{ lineHeight: '40px' }}>
            版本号：{versionNumber}
          </div>
          <div className="pull-right">
            <Tooltip title={`导入${format}`}>
              <Icon type="upload" className={styles.command} onClick={() => setVisible(true)} />
            </Tooltip>
            <Divider type="vertical" />

            <Tooltip title={globalToggle.status ? '全部收起' : '全部展开'}>
              <Icon
                type={globalToggle.status ? 'minus-square' : 'plus-square'}
                className={styles.command}
                onClick={() =>
                  dispatch({
                    type: 'open_or_close_node',
                    payload: !globalToggle.status,
                  })
                }
              />
            </Tooltip>

            {readOnly ? null : (
              <>
                <Divider type="vertical" />
                <Tooltip title="保存">
                  {!saveDataLoading ? (
                    <Icon type="save" className={styles.command} onClick={() => handleSave()} />
                  ) : (
                    <Icon type="loading" className={styles.command} />
                  )}
                </Tooltip>
              </>
            )}

            <Divider type="vertical" />
            <Tooltip title="测试">
              <Icon
                type="deployment-unit"
                className={styles.command}
                onClick={() => setShow(true)}
              />
            </Tooltip>
          </div>
        </div>

        <div className={classnames(styles.body)} style={{ height: height + 37 + 32 + 12 }}>
          {rootNode ? (
            <FilteringContainer nodes={[rootNode]} indexSearch={TreeFilter}>
              {({ nodes }) => (
                <ul className={styles.wtree} style={{ height }}>
                  <Tree
                    nodes={nodes}
                    onChange={nodes => {
                      dispatch({
                        type: 'set_the_whole_tree',
                        payload: { rootNode: nodes[0] },
                      });
                    }}
                  >
                    {({ style, node, ...rest }) => (
                      <div
                        style={{
                          ...style,
                          paddingLeft: style.marginLeft + 24,
                          marginLeft: 0,
                        }}
                        className={styles.row}
                      >
                        <Expandable
                          node={node}
                          {...rest}
                          iconsClassNameMap={{
                            expanded: `tgIcon icon-arrow-down ${styles.switcher}`,
                            collapsed: `tgIcon icon-arrow-right ${styles.switcher}`,
                            // lastChild: 'mi mi-insert-drive-file',
                          }}
                        >
                          <Node
                            nodePath={getAttrPath([rootNode], k => k.id === node.id)}
                            current={node}
                            parentId={last(node.parents)}
                            parent={getNodeById([rootNode], last(node.parents))}
                            offset={style.marginLeft}
                          />
                        </Expandable>
                      </div>
                    )}
                  </Tree>
                </ul>
              )}
            </FilteringContainer>
          ) : (
            <div
              style={{
                height: '90%',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
              }}
            >
              <SquareButton
                onClick={() => setVisible(true)}
                style={{ marginRight: '16px' }}
                icon="upload"
                text={`导入${format}报文`}
              />
              <SquareButton onClick={showDefaultPanel} icon="plus" text="手动创建" />
            </div>
          )}
        </div>

        <Modal
          visible={visible}
          width={780}
          title={`导入${format}报文`}
          onOk={() => run()}
          onCancel={() => setVisible(false)}
          destroyOnClose
          okButtonProps={{
            loading,
          }}
        >
          <CodeEditor ref={importRef} data={importMessage} mode={format} />
        </Modal>

        <Modal
          visible={show}
          width={1200}
          title="校验测试"
          onOk={() => runTest()}
          okText="开始测试"
          onCancel={() => setShow(false)}
          destroyOnClose
          okButtonProps={{
            loading: testLoading,
          }}
        >
          <Form>
            <Row gutter={16}>
              <Col span={12}>
                <Form.Item label="待校验报文">
                  <CodeEditor height={500} ref={testRef} data={importMessage} mode={format} />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="校验结果">
                  <CodeEditor height={500} ref={resultRef} data={result} mode="json" />
                </Form.Item>
              </Col>
            </Row>
          </Form>
        </Modal>
      </div>
    </Spin>
  );
}

export default ValidatorEditor;
